from django.shortcuts import render

# Create your views here.
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
# from rest_framework.status import HTTP_404_NOT_FOUND
from rest_framework.status import *

from drfstudy.models import Student, Classes

from drfstudy.serializers import StudentSerializer, ClassesSerializer

"""
get请求 用于获取页面数据
post请求 用于提交数据
视图集不提供任何的方法去处理程序 所以get和post这两个不同的方法去处理请求已经不存在了
所以需要我们自定义一些方法来操作处理 方法名也是有对应好的命名规范我们直接拿来用就可以了
  list()  通过一组数据
  retrieve()  提供单个数据
  create()  创建数据
  update()  修改数据
  destroy()  删除数据
"""

# 定义一个学生的视图集的类 让它继承视图集里面的视图集成为一个学生视图集类
# 我们可以在里面写多个方法
# class StudentViewSet(viewsets.ViewSet):
#     # 定义类方法 list方法查询多条数据 带上请求对象
#     # 查询数据：序列化器把这个对象转换成json格式的数据在传给前端 也叫做序列化
#     def list(self, request):
#         # 查询传的是模型对象也就是实例 把这个实例化对象从数据库里面拿出来给序列化器做序列化的操作
#         # 通过Student模型类对象.objects.filter(is_delete=False)    导入：Student
#         # 查询出没有被逻辑删除的对象全部让他们显示出来给到一个变量保存 就拿到了所有的学生对象了
#         # 模型是一个类 类里面的数据是一个对象 对象就是类通过实例化出来的 也叫初始化对象
#         # is_delete=False
#         student = Student.objects.filter(is_delete=False)
#         # 把查询到的数据（模型对象的查询集也就是结果集）通过序列化器转换成json格式的数据：对象{} 数组[]
#         # 把学生的序列化器类那过来 导入一下 把我们那到的学生扔进来 并且指定多条数据
#         # 把序列化转换后的数据也给到一个变量来保存 也叫实例化对象
#         # 直接传值的 初始化函数的第一个参数是instance=None 是一个实例
#         serializer = StudentSerializer(student,many=True)
#         # 序列化器保存的是一个对象 打印一下内容和类型
#         print(serializer.data, type(serializer.data))
#         # [] <class 'rest_framework.utils.serializer_helpers.ReturnList'>
#         # 列表在前端就是对象类型 也可以把它看做是数组对象 得到的上一个list列表类型的数组的格式
#
#         # 把serializer.data对象数据返回到前端去 导入：Response
#         return Response(serializer.data)
#
#     # 定义一个添加的方法
#     # 创建数据：把前端传过来的数据给到序列化器做了数据检验并保存的操作 然后把检验后的数据给到后端 后端在给到数据库做持久化保存的操作 也叫反序列化
#     def create(self, request):
#         # 对前端传过来的数据作反序列化的操作：做数据的检验 做数据的保存 放进去到数据库 是传数据给到序列化器了
#         # 前端的数据，直接默认传会传递给instance这个实例 所以需要指定参数传值 就是把获取到的前端的数据request.data指定传给data对象
#         serializer = StudentSerializer(data=request.data)
#         # is_valid()对数据进行校验 如果校验没有通过就会发送异常信息，
#         serializer.is_valid(raise_exception=True)
#         # 持久化数据 保存数据
#         serializer.save()
#
#         # 把创建出来的数据序列化进行返回
#         return Response(serializer.data)
#         # 由于序列化器还没有定义创建的方法 也就是说学生视图集类 ；StudentSerializer 的父类中的create方法里面没有写任何东西
#         # 只是抛出了没有导入的异常 也就是说没有做任何持久化的操作
#         # 所以我们要去重新定义create方法完成持久化的操作 不然你去直接调用save（）方法去进行保存的话它就会自动调用创建的方法
#         # 但是这个类里面的创建的方法什么东西都没有 调用了和没有调用一样 所以我们要自己去重写这个create方法
#         # 在哪里重写这个create方法呢？ 我们要在学生的序列化器类：StudentSerializer中自己在定义一个create方法
#
#     # 定义查询单条数据    你要查询的数据id 我们一般用pk来保存这个id
#     def retrieve(self, request, pk):
#         # pk 指定数据id 路由参数 操作模型查询指定的数据 默认把这个id设置成主键
#         try:
#             # 把模型里面的学生类也就是学生对象实例化交给一个变量student保存  导入学生类：Student
#             # 根据id查询到的学生对象
#             # 这个变量student就是一个实例对象 有可能找不到这个学生 所以要把它放到try里面
#             # student = Student.objects.get(id=pk)
#             # 加上查询的条件 is_delete=False 删除的学生就不会显示数据了
#             # 但是数据库里面的数据还是存在的 并没有把它删除掉 还是保留在数据库里面 只不过你查询不到而已
#             student = Student.objects.filter(is_delete=False).get(id=pk)
#         except Student.DoesNotExist:     # 把不存在的异常信息放在except里面
#             # 手动返回一个状态码   status=HTTP_404_NOT_FOUND  导入状态：HTTP_404_NOT_FOUND
#             # ctrl+HTTP_404_NOT_FOUND 进入status文件里面 有很多状态码 使用的时候直接去复制就可以了
#             # 把导入状态码改为 *  以后导入的时候就直接去用就可以了 就不需要再取导入了
#             return Response(status=HTTP_404_NOT_FOUND)
#
#         # 创建序列化器 让它帮我们去做序列化的操作 student是一个实例对象 它传给了instance的实例
#         # 学生对象传给序列化器，做反序列化的操作
#         serializer = StudentSerializer(student)
#         print(serializer.data)
#         # 把转换后的数据返回响应给前端
#         return Response(serializer.data)
#
#     # 定义修改的方法
#     def update(self, request, pk):
#         try:
#             # 根据id查询到的学生对象
#             student = Student.objects.get(id=pk)
#         except Student.DoesNotExist:
#             return Response(status=HTTP_404_NOT_FOUND)
#
#         # 得到用户修改后的值，也就是前端传递过来的数据，我们查询到的数据库里面的数据
#         # student就是得到的学生对象 他会给到序列化器的基础模版里面的init初始化方法来里面的instance接收
#         serializer = StudentSerializer(student, data=request.data)
#         # 校验用户输入的数据有没有问题 如果有问题就会报错
#         serializer.is_valid()
#         # 检验没有问题之后就要去做 修改 持久化保存数据的操作
#         serializer.save()  # 调用的是基础模版里面的update 方法
#         # 返回操作后的数据
#         return Response(serializer.data)
#
#     # 定义数据删除的方法：
#     def destroy(self, request, pk):
#         try:
#             # 根据id查询到的学生对象
#             student = Student.objects.get(id=pk)
#         except Student.DoesNotExist:
#             return Response(status=HTTP_404_NOT_FOUND)
#         # 调用删除的方法 其实调用的是我们自己在模型里面自己定义的删除的方法 并不是想要把学生数据删除 而是隐藏
#         student.delete()
#         # 请求是成功 但是没有内容
#         return Response(status=HTTP_204_NO_CONTENT)

# 学生视图集类
class StudentViewSet(viewsets.ModelViewSet):
    # 指定增删改查的数据集
    queryset = Student.objects.filter(is_delete=False)
    # 指定序列化器类
    serializer_class = StudentSerializer

# 班级视图集类
class ClassesViewSet(viewsets.ModelViewSet):
    queryset = Classes.objects.filter(is_delete=False)
    serializer_class = ClassesSerializer

    # 定义一个方法返回最新的班级 如果想要自己定义的这个方法也会自动的生成路由 就需要在通过action调用装饰器
    # 导入：action 选择：rest_framework.decorators.action()
    # 在装饰器里面 定义methods的请求方式 要获取最新的班级 用的是get请求
    # get方法要获取详情数据的话 有没有参数 如果要传参数id也就是pk的话 detail=True
    # 这里是通过last方法去获取数据的 所以不需要传参数 detail=False
    # api 设计 GET/classes/last
    @action(methods=['get'], detail=False)
    def last(self, request):
        # 先获取到这个班级   last()获取最后一个
        classes = Classes.objects.last()
        # ClassesSerializer(data)  把数据传给序列化器做序列化的操作
        # 数据   调用get_serializer方法
        data = self.get_serializer(classes).data
        # 把处理后的数据做一个返回的操作
        return Response(data)

    # 定义一个方法获取指定班级的最后一个学生
    # pk是班级的id
    # api设计：GET请求方式  <pk>是转换器   classes/<pk>/student/last
    # url_path 修改路由 把方法名路由修改为自定义路由
    # 装饰器的作用就是给我们自定义的方法自动生成路由 就不需要在自己写路由了 只需要把两个视图集注册到路由里面就可以了
    @action(methods=['get'], detail=True, url_path='student/last')
    # 改写方法名
    def last_student(self, request, pk):
        try:
            # 获取对应的班级  自己写的路由有可能传的数错误的班级id 所以要把它放到try里面
            classes = Classes.objects.get(id=pk)
        except Classes.DoesNotExist:      # 让它处理一下班级不存在的报错 如果班级不存在就让它返回一个状态码404的响应
            return Response(status=HTTP_404_NOT_FOUND)
        # 获取指定班级的最后一个学生给到一个变量来保存 也就是一个学生对象 也就是查询出来的模型数据也就是数据库里面的数据
        classes_student_set = classes.student_set.last()
        # 现在用的是序列化器的嵌套
        # 把获取到的学生对象给到StudentSerializer学生序列化器去处理
        # 把处理后的数据.data 交给一个变量来进行保存
        data = StudentSerializer(classes_student_set).data
        # 返回响应给到前端 把数据data传给前端
        return Response(data)





